<template>
  <div class="elm-edit f_edit">
    <elm-page-bb class="ei_edit f_edit">
      <div class="div_main_02"></div>
      <div id="main_div_02" v-loading="loading" class="div_main_02 div_transform" :style="{'min-height':canvasHeight_str,'min-width':canvaswidth_str}">
        <template v-if="!loading && item.show" v-for="item in nodeDataList">
          <div v-if="item.node_type=='start' || item.node_type=='end'" class="se_node_div"
               :style="{'width':item.width_str,'height':item.height_str,'left':item.coordinateX_str,'top':item.coordinateY_str}"
               :key="item.key_str"
               @mouseover="nodeMouseOver(item.id)" @mouseout="nodeMouseOut(item.id)">
            <div class="se_node_title_div">{{ item.title }}{{item.nodeins_status}}</div>
          </div>
          <div v-if="item.node_type=='normal'" class="normal_node_div"
               :style="{'width':item.width_str,'height':item.height_str,'left':item.coordinateX_str,'top':item.coordinateY_str}"
               :key="item.key_str"
               @mouseover="nodeMouseOver(item.id)" @mouseout="nodeMouseOut(item.id)">
            <div class="normal_node_title_div" :style="{'background-color':item.nodeins_status_color}">
              {{ item.title }}
            </div>
            <div style="width: 100%;font-size: 14px;padding-top: 8px;">
              <div style="height: 27px;">
                <span style="float: left;margin-left: 45px;">{{item.person_name}}</span>
                <i class="el-icon-arrow-right" style="float: right;margin-right: 10px;margin-top: 3px;"></i>
              </div>
            </div>
          </div>
        </template>
        <svg v-show="!loading" id="theLineContainer_02" style="width:100%;height:100%;" xmlns="http://www.w3.org/2000/svg">

        </svg>
      </div>
    </elm-page-bb>
  </div>
</template>

<script>
export default {
  data() {
    return {
      loading:true,

      DE_INFO: null,

      flowExist:false,

      param_list:[],

      nodeDataList:[],
      lineDataList:[],
      buttonList:[],

      se_nodeHeight:30,
      se_nodeWidth:160,
      nodeHeight:60,//80
      nodeWidth:160,//200
      buttonHeight:24,
      buttonwidth:24,

      lineButtonWidth:50,
      lineButtonHeight:20,
      lineButtonWidth_str:'50px',
      lineButtonHeight_str:'20px',

      rowHeight:160,
      colwidth:200,//240

      rowWithExtraHeight:{},
      extraHeightForCondition:0,//缩略图不在画布中显示条件语句框
      lineConditionWidth:160,
      lineConditionHeight:66,
      lineConditionWidth_str:'160px',
      lineConditionHeight_str:'66px',

      canvasHeight:0,
      canvaswidth:0,
      canvasHeight_str:'100px',
      canvaswidth_str:'100px',

      leftDivWidth:360,
      extraWidth_left:50,//额外的左侧宽度，用于容纳左侧信息列表（如果有）和从流程图左边外侧绕过的连线
      extraWidth_Right:50,//额外的右侧宽度，用于容纳节点右侧的浮窗和从流程图右边外侧绕过的连线

      rowInfoList:[],
      nData_forNextNodeCheck:{},

      lineObjList:[],
      lineColor:'#C7CACD',//#000CBD
      lineColorHover:'#F56C6C',

      default_node_policy:'抢签',
      default_node_pb_policy:'退首跳回',
      default_node_user_policy:'全部参与者',

      nodeCheckDataList:[],
      nodeForSelectList:[],
      tempShowSelect:false,
      temp_end_node:'',

      showFlowinsData:false,
    }
  },
  props: {
    flow_id: { type: String, default: null },
  },
  mounted() {
    this.flow_model = {'id':this.flow_id};
    this.v_getData_flow();

    let bbb = document.getElementsByClassName('elm-bottom');
    bbb[0].remove();

    //阻止原有的右键菜单
    document.addEventListener('contextmenu',function (event){
      event.preventDefault();
    },false);
  },
  methods: {
    async v_getData_flow(){
      this.loading = true;

      //如果流程尚未入库，那么先保存流程
      let check = await elm.post('/system/login/flow/GetFlowList', { "id": this.flow_model.id});
      if (check.length>0) {
        this.flowExist = true;
        this.load_editOrShow();
      }
      else{
        //初始化流程绘制数据并加载
        this.load_create();
      }
    },
    load_create:function(){
      this.loading = true;

      let nodeStart = {'id': elm.newGuid(),'title':'开始','node_type':'start'};
      let nodeEnd = {'id': elm.newGuid(),'title':'结束','node_type':'end'};
      this.nodeDataList = [nodeStart,nodeEnd];
      let line = {
        'id': elm.newGuid(),
        'start_node':nodeStart.id,
        'end_node':nodeEnd.id,
        'type':'default',
      };
      this.lineDataList = [line];

      this.nodeCheckDataList = [];

      this.loadCanvas();
    },
    async load_editOrShow(){
      this.loading = true;
      let data = await elm.post('/system/login/flow/GetCanvasData', {'flow_id':this.flow_model.id});
      let nodeList = data.nodeList;
      let lineList = data.lineList;

      this.nodeCheckDataList = [];

      let needCreate = false;
      if(nodeList.length<2 || lineList.length<1){needCreate=true;}
      else{
        let startNodeExist = false;
        let endNodeExist = false;
        for(let i=0;i<nodeList.length;i++){
          let node = nodeList[i];
          if(node.node_type=='start'){startNodeExist = true;}
          else if(node.node_type=='end'){endNodeExist = true;}
        }
        if(!startNodeExist || !endNodeExist || nodeList.length==2){needCreate=true;}
      }
      for(let i=0;i<nodeList.length;i++){
        nodeList[i]['key_str'] = nodeList[i].id;
      }
      if(needCreate){this.load_create();return;}

      //整理参与者数据
      for(let i=0;i<nodeList.length;i++){
        let node = nodeList[i];
        node['person_name'] = '';
        node['person_name_list'] = [];
        if(node.node_type=='normal'){
          let nodeCheckData = {
            'node_id':node.id,
            'check_list':[],
            'check_param_list':[],
            'need_save':'no',
            'person_num':0,
            'person_name':'',
          };
          for(let kk=0;kk<data.check_list.length;kk++){
            let item = data.check_list[kk];
            if(item.flow_node_id==nodeCheckData.node_id){
              nodeCheckData.check_list.push(item);

              if(item.iface_id=='inter_0010'){
                for(let jj=0;jj<data.check_param_list.length;jj++){
                  let paramItem = data.check_param_list[jj];
                  if(item.id==paramItem.check_id && !this.em(paramItem.org_name)){
                    nodeCheckData.person_name =nodeCheckData.person_name+'---'+paramItem.org_name;
                    nodeCheckData.person_num++;
                  }
                }
              }
              else if(item.iface_id=='inter_0020'){
                for(let jj=0;jj<data.check_param_list.length;jj++){
                  let paramItem = data.check_param_list[jj];
                  if(item.id==paramItem.check_id && !this.em(paramItem.role_name)){
                    nodeCheckData.person_name =nodeCheckData.person_name+'---'+paramItem.role_name;
                    nodeCheckData.person_num++;
                  }
                }
              }
              else if(item.iface_id=='inter_0030'){
                for(let jj=0;jj<data.check_param_list.length;jj++){
                  let paramItem = data.check_param_list[jj];
                  if(item.id==paramItem.check_id && !this.em(paramItem.uu_user_name)){
                    nodeCheckData.person_name =nodeCheckData.person_name+'---'+paramItem.uu_user_name;
                    nodeCheckData.person_num++;
                  }
                }
              }
              else if(item.iface_id=='inter_0040'){
                nodeCheckData.person_name =nodeCheckData.person_name+'---'+'直属领导';
                nodeCheckData.person_num++;}
              else if(item.iface_id=='inter_0050'){
                nodeCheckData.person_name =nodeCheckData.person_name+'---'+'流程发起人';
                nodeCheckData.person_num++;}
              else if(item.iface_id=='inter_0060'){
                nodeCheckData.person_name =nodeCheckData.person_name+'---'+'由上一节点指定';
                nodeCheckData.person_num++;}
            }
          }
          for(let kk=0;kk<data.check_param_list.length;kk++){
            let item = data.check_param_list[kk];
            if(item.flow_node_id==nodeCheckData.node_id){nodeCheckData.check_param_list.push(item);}
          }
          this.nodeCheckDataList.push(nodeCheckData);

          if(!this.em(nodeCheckData.person_name) && nodeCheckData.person_num>0){
            let nodePersonNames = nodeCheckData.person_name.split('---');
            node.person_name = nodePersonNames.length>2?nodePersonNames[1]+'…':nodePersonNames[1];
            for(let i=1;i<nodePersonNames.length;i++){ node.person_name_list.push(nodePersonNames[i]); }
          }
        }
      }

      console.log('绘制流程图……');

      this.nodeDataList = nodeList;
      this.lineDataList = lineList;
      this.loadCanvas();
    },
    checkNodeCN:function(){
      let nodeStart = null;
      let nodeEnd = null;
      let normalNodeList = [];
      for(let i=0;i<this.nodeDataList.length;i++){
        let nn = this.nodeDataList[i];
        nn['width'] = nn.node_type == 'normal'?this.nodeWidth:this.se_nodeWidth;
        nn['height'] = nn.node_type == 'normal'?this.nodeHeight:this.se_nodeHeight;
        nn['width_str'] = nn.width +'px';
        nn['height_str'] = nn.height +'px';
        nn['rowIndex'] = 0;
        nn['coordinateX'] = 0;
        nn['coordinateY'] = 0;
        nn['show'] = false;
        if(nn.node_type == 'start'){
          if(nodeStart!=null){this.$message.error('数据错误，多个开始节点');}
          nodeStart = nn;
        }
        else if(nn.node_type == 'end'){
          if(nodeEnd!=null){this.$message.error('数据错误，多个结束节点');}
          nodeEnd = nn;
        }
        else if(nn.node_type == 'normal'){
          normalNodeList.push(nn);
        }
        else {}
      }

      let rowNum = 1;
      let colmNum = 1;
      if(normalNodeList.length==0){
        nodeEnd.rowIndex=1;
      }
      else{
        ///计算总层数，计算各节点所属的层数
        //这里用节点与开始节点之间的最小连线数，做为节点所属的层数。从上到下逐层查找，此时流程图中的环形结构不会导致循环查找。
        let tempNodeIds = [nodeStart.id];
        let tempData = {};
        nodeStart['rowIndex']=0;
        for(let rrr=0;rrr<100;rrr++){
          let nextRowExist = false;
          let tempNextNodeIds = [];
          for(let i=0;i<tempNodeIds.length;i++){
            for(let j=0;j<this.lineDataList.length;j++){
              let lineItem = this.lineDataList[j];
              if(lineItem.start_node==tempNodeIds[i]){
                for(let k=0;k<this.nodeDataList.length;k++){
                  let nodeItem = this.nodeDataList[k];
                  if(lineItem.end_node==nodeItem.id && !tempData[nodeItem.id]){
                    nextRowExist = true;
                    tempNextNodeIds.push(nodeItem.id);
                    nodeItem['rowIndex'] = rowNum;

                    tempData[nodeItem.id] = true;
                  }
                }
              }
            }
          }
          if(nextRowExist){
            tempNodeIds = tempNextNodeIds;
            rowNum++;
          }
          else{rrr=1000000;}
        }

        if(tempNodeIds.length>1 || tempNodeIds[0]!=nodeEnd.id){ rowNum++; }
        nodeEnd.rowIndex=rowNum - 1;

        //计算最大列数
        for(let i=0;i<rowNum;i++){
          let tNum = 0;
          for(let k=0;k<this.nodeDataList.length;k++){
            if(this.nodeDataList[k].rowIndex==i){tNum++}
          }
          if(colmNum<tNum){colmNum=tNum;}
        }
      }

      let allColWidth = (colmNum * this.colwidth)+50;
      if(this.showFlowinsData){this.extraWidth_left=this.leftDivWidth;}
      this.canvaswidth = allColWidth + this.extraWidth_left + this.extraWidth_Right;

      if(this.canvaswidth < document.getElementById("main_div_02").clientWidth-50){
        this.canvaswidth = document.getElementById("main_div_02").clientWidth-50;
        allColWidth = this.canvaswidth - this.extraWidth_left - this.extraWidth_Right;
      }

      //计算开始和结束节点的坐标
      nodeStart.coordinateX = ((allColWidth/2)+this.extraWidth_left)-(this.se_nodeWidth/2);
      nodeStart.coordinateY = this.nodeHeight-this.se_nodeHeight;
      nodeEnd.coordinateX = nodeStart.coordinateX;
      nodeEnd.coordinateY = this.rowHeight * nodeEnd.rowIndex;
      nodeStart.show = true;
      nodeEnd.show = true;

      //计算普通节点的坐标，对于需要显示连线条件的层级，增加额外高度
      this.rowWithExtraHeight = {};
      for(let i=0;i<this.nodeDataList.length;i++){
        let nodeItem = this.nodeDataList[i];

        if(nodeItem.node_type!='normal'){}
        else if(nodeItem.rowIndex==null){console.log('未正确连结的节点被排除 '+nodeItem.id);}
        else{
          nodeItem.coordinateX = nodeStart.coordinateX - ((this.nodeWidth-this.se_nodeWidth)/2);//默认与开始节点一样居中
          nodeItem.coordinateY = this.rowHeight * nodeItem.rowIndex;
          nodeItem.show = true;
        }

        for(let kk=0;kk<this.lineDataList.length;kk++){
          let lineItem = this.lineDataList[kk];
          if(lineItem.end_node == nodeItem.id && !this.em(lineItem.condition_s) && lineItem.condition_s.indexOf('###')>=0){
            for(let kk=0;kk<this.nodeDataList.length;kk++){
              if(this.nodeDataList[kk].id==lineItem.start_node && this.nodeDataList[kk].rowIndex+1 == nodeItem.rowIndex){
                this.rowWithExtraHeight[nodeItem.rowIndex] = true;
              }
            }
          }
        }
      }
      for(let i=0;i<this.nodeDataList.length;i++){
        let nodeItem = this.nodeDataList[i];
        for(let kk=0;kk<=nodeItem.rowIndex;kk++){
          if(this.rowWithExtraHeight[kk]){
            nodeItem.coordinateY = nodeItem.coordinateY + this.extraHeightForCondition;
          }
        }
      }

      this.canvasHeight = nodeEnd.coordinateY - 50;
      this.canvasHeight_str = (this.canvasHeight+100)+'px';
      this.canvaswidth_str = this.canvaswidth+'px';

      ///
      //处理各层中普通节点的横坐标
      let main_max_x = 0;
      let rowNodeList = [[nodeStart]];
      let rowInfoList = [{'min_x':(nodeStart.coordinateX+nodeStart.width)-this.colwidth,'max_x':nodeStart.coordinateX+this.colwidth}];
      console.log('rowNum: ' + rowNum );
      for(let i=1;i<rowNum-1;i++){
        let upperNodeIds = [];
        for(let k=0;k<rowNodeList[i-1].length;k++){ upperNodeIds.push(rowNodeList[i-1][k].id); }
        let rList = this.getNextNode(upperNodeIds);
        rowNodeList.push(rList);
      }
      rowNodeList.push([nodeEnd]);
      for(let i=1;i<rowNum-1;i++){
        let rList =rowNodeList[i];
        let nodeNum = rList.length;
        console.log('row: '+rList[0].rowIndex +'; num: '+rList.length );
        let rowInfo = {'min_x':rowInfoList[0].min_x,'max_x':rowInfoList[0].max_x};
        if(nodeNum>1){
          let xx = nodeStart.coordinateX-((this.nodeWidth-this.se_nodeWidth)/2);
          let mIndex = parseInt(nodeNum/2);
          if(parseInt(nodeNum/2)*2==nodeNum){
            mIndex--;
            xx=xx-(this.colwidth/2);
          }
          let tempX = xx;
          for(let kk=mIndex;kk>=0;kk--){
            let rkkItem = rList[kk];
            rkkItem.coordinateX = tempX;
            tempX = tempX - this.colwidth;

            this.refreshRowInfo(rkkItem.coordinateX,rkkItem.width,rowInfo);
          }
          tempX = xx + this.colwidth;
          for(let kk=mIndex+1;kk<rList.length;kk++){
            let rkkItem = rList[kk];
            rkkItem.coordinateX = tempX;
            tempX = tempX + this.colwidth;

            this.refreshRowInfo(rkkItem.coordinateX,rkkItem.width,rowInfo);
          }
        }
        rowInfoList.push(rowInfo);

        if(main_max_x<rowInfo.max_x){main_max_x=rowInfo.max_x;}
      }
      //调整节点的横坐标
      //若某层的节点数多于一个，那么将该层最左侧的节点设为节点A，最右侧的节点设为节点B
      //将节点A的下级节点调整到其左侧或正下方
      //将节点B的下级节点调整到其右侧或正下方
      let tempKK_ids = {};
      for(let i=1;i<rowNum-2;i++){
        let rList =rowNodeList[i];
        if(rList.length>1){
          let nodeA = rList[0];
          let nodeB = rList[rList.length-1];
          let rowInfo = rowInfoList[i];
          let check = false;
          let tempX = 0;

          let nextListA_EE = [];
          for(let kk=1;kk<rList.length;kk++){nextListA_EE.push(rList[kk].id);}
          this.nData_forNextNodeCheck = {};
          let nextListA = this.getNextNodeFromNextListByNodeId(nodeA.id,rowNodeList[i+1]);
          if(nextListA[nextListA.length-1].coordinateX > nodeA.coordinateX || rList.length==2){
            tempX =nodeA.coordinateX;
            for(let kk=nextListA.length-1;kk>=0;kk--){
              let rkkItem = nextListA[kk];
              if(tempKK_ids[rkkItem.id]==null){
                rkkItem.coordinateX = tempX;
                tempX = tempX - this.colwidth;
                this.refreshRowInfo(rkkItem.coordinateX,rkkItem.width,rowInfo);
                tempKK_ids[rkkItem.id] = true;
              }
            }
          }

          let nextListB_EE = [];
          for(let kk=rList.length-2;kk>=0;kk--){nextListB_EE.push(rList[kk].id);}
          this.nData_forNextNodeCheck = {};
          let nextListB = this.getNextNodeFromNextListByNodeId(nodeB.id,rowNodeList[i+1]);
          tempX = nodeB.coordinateX;
          for(let kk=0;kk<nextListB.length;kk++){ if(nextListB[kk].coordinateX < nodeB.coordinateX){ check = true; } }
          if(check || rList.length==2){
            check = false;
            for(let kk=0;kk<nextListB.length;kk++){
              let rkkItem = nextListB[kk];
              if(tempKK_ids[rkkItem.id]==null){
                rkkItem.coordinateX = tempX;
                tempX = tempX + this.colwidth;
                this.refreshRowInfo(rkkItem.coordinateX,rkkItem.width,rowInfo);
                tempKK_ids[rkkItem.id] = true;
              }
            }
          }
        }
      }
      //调整节点的横坐标
      //若某层的节点数多于一个，那么将该层最左侧的节点设为节点A，最右侧的节点设为节点B
      //将节点A调整到其下级节点的右侧或正上方
      //将节点B调整到其下级节点的左侧或正上方
      ///
      ///
      ///

      this.rowInfoList = rowInfoList;
      for(let i=0;i<this.nodeDataList.length;i++){
        let nn = this.nodeDataList[i];
        nn['coordinateX_str'] = nn.coordinateX+'px';
        nn['coordinateY_str'] = nn.coordinateY+'px';
      }

      if(this.canvaswidth < main_max_x + this.extraWidth_Right){
        this.canvaswidth = main_max_x + this.extraWidth_Right;
        this.canvaswidth_str = this.canvaswidth+'px';
      }

      //刷新节点排序值
      let rNum = 0;
      for(let i=0;i<rowNodeList.length;i++){
        let rList =rowNodeList[i];
        for(let kk=0;kk<rList.length;kk++){
          let nodeData = rList[kk];
          nodeData['remark'] = this.addZero_5(rNum);
          rNum++;
        }
      }

      return true;
    },
    refreshRowInfo:function(coordinateX,itemWith,rowInfo){
      let rr_min_x =(coordinateX+itemWith)-this.colwidth;
      let rr_max_x =coordinateX+this.colwidth;
      if(rowInfo.min_x>rr_min_x){rowInfo.min_x = rr_min_x;}
      if(rowInfo.max_x<rr_max_x){rowInfo.max_x = rr_max_x;}
    },
    loadCanvas(){
      this.loading = true;
      let check = this.checkNodeCN();
      if(!check){return;}

      //节点信息，用于连线指向选择
      this.nodeForSelectList = [];
      for(let i=0;i<this.nodeDataList.length;i++){
        let nodeData = this.nodeDataList[i];
        if(nodeData.node_type!='start'){
          this.nodeForSelectList.push({'id':nodeData.id,'node_type':nodeData.node_type,'title':nodeData.title,'remark':nodeData.remark});
        }
      }

      let buttonList = [];
      let nodeWithButtonUpon = {};
      let nodeWithButtonbuttonBehind = {};

      //去除从开始节点指向结束节点的连线（如果有其他起始节点的连线）
      let lineDataList = [];
      let ss_start_node_id = '';
      let ss_end_node_id = '';
      for(let i=0;i<this.nodeDataList.length;i++){
        let nodeData = this.nodeDataList[i];
        if(nodeData.node_type=='start'){ss_start_node_id = nodeData.id;}
        else if(nodeData.node_type=='end'){ss_end_node_id = nodeData.id;}
      }
      let seCheck = false;
      let otherCheck = false;
      for(let i=0;i<this.lineDataList.length;i++){
        let lineData = this.lineDataList[i];
        if(lineData.start_node==ss_start_node_id && lineData.end_node==ss_end_node_id){seCheck = true;}
        else{
          lineDataList.push(lineData);
          otherCheck = true;
        }
      }
      if(seCheck && otherCheck){this.lineDataList = lineDataList;}

      //去除重复连线（如果有）
      let newLineList = [];
      for(let i=0;i<this.lineDataList.length;i++){
        let lineData = this.lineDataList[i];
        let check = true;
        for(let kk=0;kk<newLineList.length;kk++){
          let checkLineData = newLineList[kk];
          if(lineData.start_node==checkLineData.start_node && checkLineData.end_node==lineData.end_node){check = false;}
        }
        if(check){ newLineList.push(lineData); }
      }
      this.lineDataList = newLineList;

      if(this.showFlowinsData){
        for(let i=0;i<this.nodeDataList.length;i++){
          let nodeData = this.nodeDataList[i];
          nodeData['nodeins_status_color'] = '#C0C0C0';
          if(this.nodeinsData[nodeData.id]!=null){
            nodeData['nodeins_status'] = this.nodeinsData[nodeData.id].status;
            if(nodeData.nodeins_status=='running'){nodeData.nodeins_status_color='#3296F8';}
            else if(nodeData.nodeins_status=='completed'){nodeData.nodeins_status_color='#45B964';}//#67C26C
            else if(nodeData.nodeins_status=='waiting'){nodeData.nodeins_status_color='#F4B962';}

            nodeData['nodeins_person_names'] = this.nodeinsData[nodeData.id].nodeins_person_names;
            nodeData['nodeins_start_time'] = this.nodeinsData[nodeData.id].nodeins_start_time;
            nodeData['nodeins_end_time'] = this.nodeinsData[nodeData.id].nodeins_end_time;
            nodeData['pb_text'] = this.nodeinsData[nodeData.id].pb_text;
          }
        }
        for(let i=0;i<this.lineDataList.length;i++){
          let lineData = this.lineDataList[i];
          lineData['has_lineins'] = false;
          for(let kk=0;kk<this.lineinsList.length;kk++){
            let lineins = this.lineinsList[kk];
            if(lineData.start_node == lineins.start_node && lineData.end_node == lineins.end_node){
              lineData['has_lineins'] = true;
            }
          }
        }
      }

      //添加节点附近的按钮
      //计算连线的绘制数据
      for(let i=0;i<this.lineDataList.length;i++){
        let lineItem = this.lineDataList[i];

        //若一条连线是某个节点的唯一传入连线，那么禁止修改指向、禁止删除
        //若一条连线是某个节点的唯一传出连线，那么禁止删除
        //若一条连线是某个节点的唯一传出连线，且是某个节点除从下往上类型连线以外的唯一传入连线，那么禁止修改指向
        lineItem['allow_delete']=true;
        lineItem['allow_change_to_node']=true;
        let found = false;
        for(let jj=0;jj<this.lineDataList.length;jj++){
          if(this.lineDataList[jj].end_node==lineItem.end_node && this.lineDataList[jj].start_node!=lineItem.start_node){
            found = true;
          }
        }
        if(!found){lineItem.allow_delete=false;lineItem.allow_change_to_node=false;}
        found = false;
        for(let jj=0;jj<this.lineDataList.length;jj++){
          if(this.lineDataList[jj].start_node==lineItem.start_node && this.lineDataList[jj].end_node!=lineItem.end_node) {
            found = true;

            let startNodeIndex = 0;
            let endNodeIndex = 0;
            for(let k=0;k<this.nodeDataList.length;k++){
              let nodeItem = this.nodeDataList[k];
              if(this.lineDataList[jj].start_node==nodeItem.id){startNodeIndex=nodeItem.rowIndex;}
              else if(this.lineDataList[jj].end_node==nodeItem.id){endNodeIndex=nodeItem.rowIndex;}
            }
            if(startNodeIndex<=endNodeIndex){found=true;}
          }
        }
        if(!found){
          lineItem.allow_delete=false;

          found = false;
          for(let jj=0;jj<this.lineDataList.length;jj++){
            if(this.lineDataList[jj].end_node==lineItem.end_node && this.lineDataList[jj].start_node!=lineItem.start_node){
              let startNodeIndex = 0;
              let endNodeIndex = 0;
              for(let k=0;k<this.nodeDataList.length;k++){
                let nodeItem = this.nodeDataList[k];
                if(this.lineDataList[jj].start_node==nodeItem.id){startNodeIndex=nodeItem.rowIndex;}
                else if(this.lineDataList[jj].end_node==nodeItem.id){endNodeIndex=nodeItem.rowIndex;}
              }
              if(startNodeIndex<=endNodeIndex){found=true;}
            }
          }
          if(!found){lineItem.allow_change_to_node=false;}
        }


        let startNode = null;
        let endNode = null;
        for(let k=0;k<this.nodeDataList.length;k++){
          let nodeItem = this.nodeDataList[k];
          if(nodeItem.id == lineItem.start_node){
            startNode = {
              'rowIndex':nodeItem.rowIndex,
              'height':nodeItem.height,'width':nodeItem.width,
              'coordinateX':nodeItem.coordinateX,'coordinateY':nodeItem.coordinateY,
              'left_x':nodeItem.coordinateX,
              'middle_x':nodeItem.coordinateX+(nodeItem.width/2),
              'right_x':nodeItem.coordinateX+nodeItem.width,
              'top_y':nodeItem.coordinateY,
              'middle_y':nodeItem.coordinateY+(nodeItem.height/2),
              'bottom_y':nodeItem.coordinateY+nodeItem.height,
            };

            //在节点下方显示按钮
            if(!nodeWithButtonbuttonBehind[nodeItem.id]){
              nodeWithButtonbuttonBehind[nodeItem.id] = true;
              let buttonData = {
                'type':'on-line-from-node',
                'node_id':nodeItem.id,
                'node_title':nodeItem.title,
                'node_type':nodeItem.node_type,
                'coordinateX_str':( startNode.middle_x - 12 ) + 'px',
                'coordinateY_str':( nodeItem.coordinateY + nodeItem.height + 10 ) + 'px',
              };
              buttonList.push(buttonData);
            }
          }
          else if(nodeItem.id == lineItem.end_node){
            endNode = {
              'rowIndex':nodeItem.rowIndex,
              'height':nodeItem.height,'width':nodeItem.width,
              'coordinateX':nodeItem.coordinateX,'coordinateY':nodeItem.coordinateY,
              'left_x':nodeItem.coordinateX,
              'middle_x':nodeItem.coordinateX+(nodeItem.width/2),
              'right_x':nodeItem.coordinateX+nodeItem.width,
              'top_y':nodeItem.coordinateY,
              'middle_y':nodeItem.coordinateY+(nodeItem.height/2),
              'bottom_y':nodeItem.coordinateY+nodeItem.height,
            };

            //不在节点上方显示按钮
            /*
            if(!nodeWithButtonUpon[nodeItem.id]){
              nodeWithButtonUpon[nodeItem.id] = true;
              let buttonData = {
                'type':'on-line-to-node',
                'node_id':nodeItem.id,
                'node_title':nodeItem.title,
                'node_type':nodeItem.node_type,
                'coordinateX_str':( endNode.middle_x - 12 ) + 'px',
                'coordinateY_str':( nodeItem.coordinateY - this.buttonHeight - 12 ) + 'px',
              };
              buttonList.push(buttonData);
            }
            */
          }
        }

        if(startNode!=null && endNode !=null){
          if(true || lineItem.type=='default'){
            this.setLineByNode(lineItem,startNode,endNode);
            lineItem['show'] = true;
          }
        }
      }

      this.buttonList = buttonList;

      //添加连线
      for(let i=0;i<this.lineObjList.length;i++){
        document.getElementById("theLineContainer_02").removeChild(this.lineObjList[i]);
      }
      this.lineObjList = [];
      for(let i=0;i<this.lineDataList.length;i++){
        let lineItem = this.lineDataList[i];

        let line_color = this.lineColor;
        if(lineItem.has_lineins){line_color = '#8DC473';}//#67C26C

        let c = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        c.setAttribute('id', lineItem.id+'_show');//elm.newGuid()
        c.setAttribute('d', lineItem.d_str);
        c.setAttribute('fill', 'transparent');
        c.setAttribute('stroke', line_color);
        //c.setAttribute('marker-end', 'url(#markerArrow)');//因为出现标记错位现象，这里改为手动画箭头
        //c.addEventListener('contextmenu', function () { openrmenudiv(); });
        document.getElementById("theLineContainer_02").appendChild(c);
        this.lineObjList.push(c);
        let c_marker = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        c_marker.setAttribute('id', lineItem.id+'_show'+'_marker');//elm.newGuid()
        c_marker.setAttribute('d', lineItem.line_marker_str);
        c_marker.setAttribute('fill', line_color);
        c_marker.setAttribute('stroke', line_color);
        document.getElementById("theLineContainer_02").appendChild(c_marker);
        this.lineObjList.push(c_marker);
      }

      this.consoleCanvas();

      this.loading = false;
    },
    lineMouseOver:function(line_id){
      let c = document.getElementById(line_id+'_show');
      c.setAttribute('stroke', this.lineColorHover);
      c.setAttribute('stroke-width', '7');
      c.setAttribute('stroke-dasharray', '1');
    },
    lineMouseOut:function(line_id){
      let c = document.getElementById(line_id+'_show');
      c.setAttribute('stroke', this.lineColor);
      c.setAttribute('stroke-width', '1');
      c.setAttribute('stroke-dasharray', '0');
    },
    setLineByNode:function(lineItem,startNode,endNode){
      //lineItem['line_style'] = { 'fill': 'transparent', 'stroke': '#000CBD', };
      //lineItem['line_marker_style'] = { 'fill': '#000CBD', 'stroke': '#000CBD' };

      lineItem['d_str'] = 'M20 10 L20 40';
      //lineItem['d_str'] = 'M20 10 T20 40 T20 140';
      lineItem['line_marker_str'] = 'M17 20 L23 20 L20 23';

      let sLength = 55;
      let eLength = this.lineButtonHeight + 30;

      lineItem['show_condition'] = true;
      //lineItem['condition_s_str'] = this.turnLineCondition_S_Str(lineItem.condition_s);//将连线的条件语句中的数据表列名，替换为表单项名称
      lineItem['condition_exist'] = !this.em(lineItem.condition_s_str);
      //判断是否有未被替换的数据表列名
      if(lineItem.condition_exist && lineItem.condition_s_str.indexOf('####@')>=0){
        lineItem['condition_s_str_wrong'] = true;
      }

      let s_y = startNode.bottom_y + 45;
      let e_x = endNode.middle_x;
      if(startNode.rowIndex==(endNode.rowIndex-1)){
        if(startNode.left_x == endNode.left_x){
          lineItem.d_str = 'M'+startNode.middle_x+' '+startNode.bottom_y+' L'+endNode.middle_x+' '+endNode.top_y+'';
        }
        else if(startNode.left_x > endNode.left_x){
          //e_x = (endNode.middle_x+10);
          let turnStr = ' L'+startNode.middle_x+' '+s_y+' L'+e_x+' '+s_y;
          lineItem.d_str = 'M'+startNode.middle_x+' '+startNode.bottom_y + turnStr  +' L'+e_x+' '+endNode.top_y+'';
        }
        else{
          //e_x = (endNode.middle_x-10);
          let turnStr = ' L'+startNode.middle_x+' '+s_y+' L'+e_x+' '+s_y;
          lineItem.d_str = 'M'+startNode.middle_x+' '+startNode.bottom_y + turnStr  +' L'+e_x+' '+endNode.top_y+'';
        }
        lineItem.line_marker_str = 'M'+(e_x-3)+' '+(endNode.top_y-4)+' L'+(e_x+3)+' '+(endNode.top_y-4)+' L'+e_x+' '+endNode.top_y+'';

        let line_button_x = endNode.left_x + ((endNode.width-this.lineButtonWidth)/2);
        let line_button_y = endNode.top_y - this.lineButtonHeight - 20;
        lineItem['line_button_x_str'] = line_button_x + 'px';
        lineItem['line_button_y_str'] = line_button_y + 'px';
        lineItem['line_condition_x_str'] = line_button_x - ((this.lineConditionWidth-this.lineButtonWidth)/2) + 'px';
        lineItem['line_condition_y_str'] = (line_button_y - this.lineConditionHeight - 10) + 'px';
      }
      else if(startNode.rowIndex<(endNode.rowIndex-1)){
        //由于前面的节点层级查找策略，此时endNode为结束节点
        let t_x = 0;
        let line_condition_x = 0;
        if(startNode.right_x<this.rowInfoList[0].max_x){
          let min_x = startNode.left_x;
          for(let i=startNode.rowIndex;i<this.rowInfoList.length;i++){
            if(this.rowInfoList[i].min_x<min_x){min_x = this.rowInfoList[i].min_x;}
          }
          t_x = min_x-20;
          line_condition_x = t_x - this.lineConditionWidth + (this.lineButtonWidth/2);
        }
        else{
          let max_x = startNode.right_x;
          for(let i=startNode.rowIndex;i<this.rowInfoList.length;i++){
            if(this.rowInfoList[i].max_x>max_x){max_x = this.rowInfoList[i].max_x;}
          }
          t_x = max_x+20;
          line_condition_x = t_x - (this.lineButtonWidth/2);
        }

        let turnStr = ' L'+startNode.middle_x+' '+s_y+' L'+t_x+' '+s_y+' L'+t_x+' '+(endNode.top_y-10)+' L'+endNode.middle_x+' '+(endNode.top_y-10);
        lineItem.d_str = 'M'+startNode.middle_x+' '+startNode.bottom_y + turnStr  +' L'+endNode.middle_x+' '+endNode.top_y+'';
        lineItem.line_marker_str = 'M'+(endNode.middle_x-3)+' '+(endNode.top_y-4)+' L'+(endNode.middle_x+3)+' '+(endNode.top_y-4)+' L'+endNode.middle_x+' '+endNode.top_y+'';

        let line_button_x = t_x - (this.lineButtonWidth/2);
        let line_button_y = endNode.top_y - this.lineButtonHeight - 20;
        lineItem['line_button_x_str'] = line_button_x + 'px';
        lineItem['line_button_y_str'] = line_button_y + 'px';
        lineItem['line_condition_x_str'] = line_condition_x + 'px';
        lineItem['line_condition_y_str'] = (line_button_y - this.lineConditionHeight - 10) + 'px';
      }
      else if(startNode.rowIndex>=endNode.rowIndex){
        let t_x = 0;
        let before_end_y = endNode.top_y-eLength-10;
        let end_x = endNode.left_x+20;
        let line_condition_x = 0;
        if(startNode.right_x<this.rowInfoList[0].max_x){
          let min_x = startNode.left_x;
          for(let i=endNode.rowIndex;i<=startNode.rowIndex;i++){
            if(this.rowInfoList[i].min_x<min_x){min_x = this.rowInfoList[i].min_x;}
          }
          t_x = min_x-10;
          line_condition_x = t_x - this.lineConditionWidth + (this.lineButtonWidth/2);
        }
        else{
          let max_x = startNode.right_x;
          for(let i=endNode.rowIndex;i<=startNode.rowIndex;i++){
            if(this.rowInfoList[i].max_x>max_x){max_x = this.rowInfoList[i].max_x;}
          }
          t_x = max_x+10;

          end_x = endNode.right_x-20;
          //before_end_y = endNode.top_y-eLength-15;
          line_condition_x = t_x - (this.lineButtonWidth/2);
        }

        let turnStr = ' L'+startNode.middle_x+' '+(s_y-5)+' L'+t_x+' '+(s_y-5)+' L'+t_x+' '+before_end_y+' L'+end_x+' '+before_end_y;
        lineItem.d_str = 'M'+startNode.middle_x+' '+startNode.bottom_y + turnStr  +' L'+end_x+' '+endNode.top_y+'';

        lineItem.line_marker_str = 'M'+(end_x-3)+' '+(endNode.top_y-4)+' L'+(end_x+3)+' '+(endNode.top_y-4)+' L'+end_x+' '+endNode.top_y+'';

        let line_button_x = t_x - (this.lineButtonWidth/2);
        let line_button_y = endNode.bottom_y + 10;
        lineItem['line_button_x_str'] = line_button_x + 'px';
        lineItem['line_button_y_str'] = line_button_y + 'px';
        lineItem['line_condition_x_str'] = line_condition_x + 'px';
        lineItem['line_condition_y_str'] = (line_button_y - this.lineConditionHeight - 10) + 'px';
      }
    },

    nodeMouseOver:function(node_id){
      for(let i=0;i<this.lineDataList.length;i++){
        let lineData = this.lineDataList[i];
        if(lineData.start_node==node_id){ this.lineMouseOver(lineData.id); }// || lineData.end_node==node_id
      }
    },
    nodeMouseOut:function(node_id){
      for(let i=0;i<this.lineDataList.length;i++){
        let lineData = this.lineDataList[i];
        if(lineData.start_node==node_id){ this.lineMouseOut(lineData.id); }// || lineData.end_node==node_id
      }
    },

    getNextNode:function(upperNodeIds){
      let nextList = [];
      this.nData_forNextNodeCheck = {};
      for(let i=0;i<upperNodeIds.length;i++){
        let rightUpperNodeIds = [];
        for(let k=i+1;k<upperNodeIds.length;k++){ rightUpperNodeIds.push(upperNodeIds[k]); }

        let nList = this.getNextNodeByNodeId(upperNodeIds[i],rightUpperNodeIds);
        for(let k=0;k<nList.length;k++){
          nextList.push(nList[k]);
        }
      }
      return nextList;
    },
    getNextNodeByNodeId:function(node_id,rightUpperNodeIds){
      //这里只从下一层节点中查找
      let rowIndex = 0;
      for(let k=0;k<this.nodeDataList.length;k++){
        if(this.nodeDataList[k].id==node_id){
          rowIndex = this.nodeDataList[k].rowIndex;
          break;
        }
      }

      let nextList = [];
      for(let i=0;i<this.lineDataList.length;i++){
        let lineData = this.lineDataList[i];
        if(lineData.start_node==node_id){
          for(let k=0;k<this.nodeDataList.length;k++){
            let nodeData = this.nodeDataList[k];
            if(nodeData.rowIndex == rowIndex +1 && !this.nData_forNextNodeCheck[nodeData.id] && nodeData.node_type=='normal'){
              if(nodeData.id==lineData.end_node && nodeData.id!=node_id){
                nextList.push(nodeData);
                this.nData_forNextNodeCheck[nodeData.id] = true;
              }
            }
          }
        }
      }
      //对nextList中元素按remark值排序
      for(let i=0;i<nextList.length;i++){
        for(let k=i+1;k<nextList.length;k++){
          try {
            if(parseInt(nextList[i].remark)>parseInt(nextList[k].remark)){
              let temp = nextList[i];
              nextList[i]= nextList[k];
              nextList[k] = temp;
            }
          }catch{}
        }
      }

      //设node_id对于节点为upperNode
      //对于nextList，将被多个上一层节点连结的节点设为b类节点，其他节点设为a类节点。
      //由于本次查找中，已按nodeData排除了被upperNode左侧节点连结的节点，因此将a类节点放在nextList的左侧，b类节点放在nextList的右侧
      //若传入的 turnAB 值为true，那么将a类节点放在右侧，b类节点放在左侧
      let aList = [];
      let bList = [];
      let bData = {};
      let nList = [];
      for(let k=0;k<rightUpperNodeIds.length;k++){
        for(let i=0;i<nextList.length;i++){
          let nextNode = nextList[i];
          if(!bData[nextNode.id] && this.isUpperNode(rightUpperNodeIds[k],nextNode.id)){
            bList.push(nextNode);
            bData[nextNode.id] = true;
          }
        }
      }
      for(let i=0;i<nextList.length;i++){
        let nextNode = nextList[i];
        if(!bData[nextNode.id]){ aList.push(nextNode); }
      }
      if(aList.length>2){
        //从左到右检查aList中的节点
        //对于一次检查针对的节点A,进一步检查其右侧是否有与其共同连结某个节点的节点B,将节点B放到节点A的临近右侧
        for(let i=0;i<aList.length-1;i++){
          for(let k=aList.length-1;k>i;k--){
            if(this.checkNode_SameToNode(aList[i].id,aList[k].id)){
              aList = this.turnListItem_02(aList,i,k);
            }
          }
        }
      }
      if(bList.length>2){
        //从左到右检查bList中的节点
        //对于一次检查针对的节点A,进一步检查其右侧是否有与其共同连结某个节点的节点B,将节点B放到节点A的临近右侧
        for(let i=0;i<bList.length-1;i++){
          for(let k=bList.length-1;k>i;k--){
            if(this.checkNode_SameToNode(bList[i].id,bList[k].id)){
              bList = this.turnListItem_02(bList,i,k);
            }
          }
        }
      }

      for(let i=0;i<aList.length;i++){ nList.push(aList[i]); }
      for(let i=0;i<bList.length;i++){ nList.push(bList[i]); }
      nextList = nList;

      return nextList;
    },
    getNextNodeFromNextListByNodeId(node_id,nextNodeDataList){
      let nextList = [];
      for(let i=0;i<nextNodeDataList.length;i++){
        if(this.isUpperNode(node_id,nextNodeDataList[i].id)){ nextList.push(nextNodeDataList[i]); }
      }
      return nextList;
    },
    isUpperNode:function(nodeA_id,nodeB_id){
      for(let i=0;i<this.lineDataList.length;i++){
        let lineData = this.lineDataList[i];
        if(lineData.start_node==nodeA_id && lineData.end_node==nodeB_id){return true;}
      }
      return false;
    },
    checkNode_SameToNode:function(nodeA_id,nodeB_id){//检查两节点的传入连线之间是否有指向节点相同的情况
      if(nodeA_id==nodeB_id){return false;}
      for(let i=0;i<this.lineDataList.length;i++){
        let lineData = this.lineDataList[i];
        if(lineData.start_node==nodeA_id){
          for(let k=0;k<this.lineDataList.length;k++){
            if(lineData.end_node==this.lineDataList[k].end_node && this.lineDataList[k].start_node==nodeB_id){
              return true;
            }
          }
        }
      }
      return false;
    },
    turnListItem_01:function(list,indexA,indexB){//交换数组中元素位置
      if(indexA==indexB){return list;}

      let newList = [];
      for(let i=0;i<list.length;i++){
        if(i==indexA){newList.push(list[indexB]);}
        else if(i==indexB){newList.push(list[indexA]);}
        else{newList.push(list[i]);}
      }
      return newList;
    },
    turnListItem_02:function(list,indexA,indexB){//把数组中indexB元素移到indexA元素的后边
      if(indexA==indexB || indexB-indexA==1){return list;}

      let newList = [];
      for(let i=0;i<list.length;i++){
        if(i==indexA){newList.push(list[indexA]);newList.push(list[indexB]);}
        else if(i==indexB){}
        else{newList.push(list[i]);}
      }
      return newList;
    },

    consoleCanvas:function(){},

    v_cancle:function (){
      this.close();//extends: elmVueBase
    },

    //补零
    addZero_5:function(num){
      if(num<10){return '0000'+num;}
      else if(num<100){return '000'+num;}
      else if(num<1000){return '00'+num;}
      else if(num<10000){return '0'+num;}
      else {return num;}
    },

    em: function (s) {
      if (s == null || s == '') { return true; }
      else { return false; }
    },
  }
}
</script>

<style>
.div_transform{
  transform: scale(0.65);
  transform-origin: 25% 0%;
  /*border: 1px red solid;*/
}
</style>

<style>
.f_edit .elm-body{padding: 5px;}

path:hover {
  /*pointer-events: all;*/
  /*fill: red;*/
  stroke: #F56C6C;
  stroke-width: 7;
  stroke-dasharray:1;
}

.div_main_02{
  padding: 0px !important;
  position: absolute;
  left:0px;
  top:0px;
  height:calc(100% - 3px);
  width:calc(100% - 2px);
  background-color: #F6F5F8;
  overflow: hidden;
}
.se_node_div{
  position: absolute;
  background-color: #FFFFFF;
  color:#C7CACD;
  text-align: center;
  border: 1px #C7CACD solid;
  border-radius: 3px;
//box-shadow: 0px 0px 3px rgba(0,0,0,0.5);
}
.normal_node_div{
  position: absolute;
  border-radius: 3px;
  box-shadow: 0px 0px 3px rgba(0,0,0,0.5);
  background-color: #FFFFFF;
  color: #666666;
  overflow: visible;
}
.se_node_title_div{
  font-size: 14px;
  font-weight: normal;
  margin-top: 4px;
}
.normal_node_title_div{
  width: calc(100% - 12px);
  border-radius: 3px 3px 0px 0px;
  height: 22px;
  background-color: #3296f9;
  color: #ffffff;
  text-align: left;
  font-size: 14px;
  padding-left: 12px;
  padding-top: 2px;
}
.button_icon{
  position: absolute;
  font-size: 24px;
  color: #3E96EF;
  background-color: #F6F5F8;
}

.div_left{
  position: absolute;
  left:0px;
  top:0px;
  height:100%;
  overflow-y: scroll;
  background-color: #FFFFFF;
}
.div_left_box{
  height: 110px;
  width: 100%;
}
.nodeins_log_div_left{
  float: left;
  width: 100px;
  height: 100%;
}
.nodeins_log_div_left_icon{
  position: relative;
  left:50px;
  top:40px;
  height: 30px;
}
.nodeins_log_div_left_line_01{
  position: relative;
  left:80px;
  top:22px;
  width: 18px;
  height: 0px;
  border: 1px red solid;
}
.nodeins_log_div_left_line_02{
  position: relative;
  left:65px;
  top:-37px;
  height: 40px;
  width: 0px;
  border: 1px red solid;
}
.nodeins_log_div_left_line_03{
  position: relative;
  left:65px;
  top:-7px;
  height: 40px;
  width: 0px;
  border: 1px red solid;
}
.nodeins_log_div{
  float: left;
  padding: 16px;
  width: 180px;
  height: calc(100% - 52px);
  margin-top: 10px;
  border-radius: 3px;
  box-shadow: 0px 0px 3px rgba(0,0,0,0.2);
  color: #666666;
}

.line_condition_div{
  position: absolute;
  background-color: #FFFFFF;
  box-shadow: 0px 0px 3px rgba(0,0,0,0.3);
  font-size: 14px;
  color: #3296F9;
  text-align: center;
  overflow: visible;
  border-radius: 10px;
}
.line_condition_text_div{
  margin-top: 0px;
  white-space: nowrap;
  overflow: hidden;
}

.p_item_div{
  background-color: #f9f9f9;
  border-radius: 5px;
  height: 40px;
  padding-top: 10px;
  padding-left: 10px;
  cursor:Pointer;
}
.p_item_div_left{
  float: left;
  background-color: #FFFFFF;
  border-radius: 15px;
  height: 32px;
  width: 32px;
  text-align: center;
  box-shadow: 0px 0px 3px rgba(0,0,0,0.2);
}
.p_item_div_text{
  float: left;
  padding-top: 7px;
  font-size: 14px;
  width: 90px;
  padding-left: 10px;
  text-align: left;
}
</style>